/**
 *
 * @author Doan Tuan Anh
 */

import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.Graphics;
import java.util.Random;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.media.Player;
import javax.microedition.media.Manager;

public class GameLayerManager extends LayerManager {

  static int CANVAS_X;
  static int CANVAS_Y;

  static int DISP_WIDTH;
  static int DISP_HEIGHT;

  private Duck duck;

  private ClownFish[] clownFishes;
  private GoldFish[] goldFishes;
  private Piranha[] piranhas;
  private Heart[] hearts;
  private Splash splash;

  private boolean myLeft;

  private int myCurrentLeftX;

  void setLeft(boolean left) {
    myLeft = left;
  }

  Splash getSplash()
  {
      return splash;
  }
  
  Heart[] getHearts()
  {
      return hearts;
  }
  
  Duck getDuck()
  {
      return duck;
  }
  
  ClownFish[] getClownFishes()
  {
      return clownFishes;
  }
  
  GoldFish[] getGoldFishes()
  {
      return goldFishes;
  }
  
  Piranha[] getPiranhas()
  {
      return piranhas;
  }

  void setWidth(int width)
  {
      DISP_WIDTH = width;
  }
  
  void setHeight(int height)
  {
      DISP_HEIGHT = height;
  }
  
  final int DUCK_X = 90;
  final int DUCK_Y = 40;
  final int[] fish_pos = {100, 140, 180};
  final Random random;
  
  private Sprite bonus3, bonus4, bonus5, bonus6;
  private int numAppears;
  private boolean isAppearing;
  private final int MAX_APPEARS = 20;
  private final int bonusX = 10;
  private final int bonusY = 100;
  Player waterSound, eatingSound;
  
  public GameLayerManager(int x, int y, int width, int height) throws Exception {
      
    CANVAS_X = x;
    CANVAS_Y = y;
    DISP_WIDTH = width;
    DISP_HEIGHT = height;
    
    waterSound = Manager.createPlayer(getClass().getResourceAsStream("/water001.mp3"),"audio/mpeg"); 
    eatingSound = Manager.createPlayer(getClass().getResourceAsStream("/Flop.wav"),"audio/x-wav"); 
    
    waterSound.realize();
    eatingSound.realize();
    
    bonus3 = new Sprite(Image.createImage("/bonus3.png"));
    bonus4 = new Sprite(Image.createImage("/bonus4.png"));
    bonus5 = new Sprite(Image.createImage("/bonus5.png"));
    bonus6 = new Sprite(Image.createImage("/bonus6.png"));
    
    bonus3.setRefPixelPosition(bonusX, bonusY);
    bonus4.setRefPixelPosition(bonusX, bonusY);
    bonus5.setRefPixelPosition(bonusX, bonusY);
    bonus6.setRefPixelPosition(bonusX, bonusY);
    
    bonus3.setVisible(false);
    bonus4.setVisible(false);
    bonus5.setVisible(false);
    bonus6.setVisible(false);
    
    append(bonus3);
    append(bonus4);
    append(bonus5);
    append(bonus6);
    
    numAppears = 0;
    isAppearing = true;
    previousColliding = 0;
    
    random = new Random();
    
    setViewWindow(0, 0, DISP_WIDTH, DISP_HEIGHT);
    
    if(splash == null) 
    {
        splash = new Splash(0, 0);
        append(splash);
    }
    
    if(hearts == null) 
    {      
        hearts = new Heart[5];
        hearts[0] = new Heart(width - 120, 15);
        hearts[1] = new Heart(width - 95, 15);
        hearts[2] = new Heart(width - 70, 15);
        hearts[3] = new Heart(width - 45, 15);
        hearts[4] = new Heart(width - 20, 15);
        
        for(int i = 0; i < hearts.length; i++) append(hearts[i]);
    }
    if(duck == null) {
      duck = new Duck(DUCK_X, DUCK_Y, splash, waterSound, eatingSound);
      append(duck); 
    }
    
    if(goldFishes == null)
    {
        goldFishes = new GoldFish[3];
        goldFishes[0] = new GoldFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
        goldFishes[1] = new GoldFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
        goldFishes[2] = new GoldFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
        
        for(int i = 0; i < goldFishes.length; i++) append(goldFishes[i]);
    } 
 
    if(clownFishes == null) {
      clownFishes = new ClownFish[3];
      clownFishes[0] = new ClownFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
      clownFishes[1] = new ClownFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
      clownFishes[2] = new ClownFish(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
    
      for(int i = 0; i < clownFishes.length; i++) append(clownFishes[i]);
    }
    
    
    if(piranhas == null)
    {
        piranhas = new Piranha[2];
        piranhas[0] = new Piranha(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
        piranhas[1] = new Piranha(random.nextInt(2) == 0, fish_pos[random.nextInt(fish_pos.length)]);
        
        for(int i = 0; i < piranhas.length; i++) append(piranhas[i]);
    }
  }
 
  void startWaterSound()
  {
      try
      {
          waterSound.start();
      }
      catch(Exception e)
      {
      }
  }
  
  void reset() 
  {
     if(bonus3 != null) bonus3.setVisible(false);
     if(bonus4 != null) bonus4.setVisible(false);
     if(bonus5 != null) bonus5.setVisible(false);
     if(bonus6 != null) bonus6.setVisible(false);
      
     numAppears = 0;
     isAppearing = false;
     previousColliding = 0;
      
     if(splash != null) splash.reset();
      
     if(duck != null) duck.reset();
     
     if(hearts != null)
        for(int i = 0; i < hearts.length; i++) hearts[i].reset();
     
     if(clownFishes != null)
         for(int i = 0; i < clownFishes.length; i++) clownFishes[i].reset();
     
     if(goldFishes != null)
         for(int i = 0; i < goldFishes.length; i++) goldFishes[i].reset();
     
     if(piranhas != null)
         for(int i = 0; i < piranhas.length; i++) piranhas[i].reset();
  }

  public void paint(Graphics g) {
    setViewWindow(myCurrentLeftX, 0, DISP_WIDTH, DISP_HEIGHT);
    paint(g, CANVAS_X, CANVAS_Y);
  }

  private int previousColliding;
  private final int MASK = (1 << 3) - 1;
  
  int advance(int gameTicks) {
    int retVal = 0;

    for(int i = 0; i < goldFishes.length; i++)
        for(int j = i + 1; j < goldFishes.length; j++) goldFishes[i].checkCollision(goldFishes[j]);
    
    for(int i = 0; i < clownFishes.length; i++)
        for(int j = i + 1; j < clownFishes.length; j++) clownFishes[i].checkCollision(clownFishes[j]);
    
    for(int i = 0; i < piranhas.length; i++)
        for(int j = i + 1; j < piranhas.length; j++) piranhas[i].checkCollision(piranhas[j]);
    
    boolean colliding = false;
    
    int numCombo = 0;
    
    for(int i = 0; i < clownFishes.length; i++)
    {
        int num = duck.checkCollision(clownFishes[i]);
        retVal += num;
        colliding |= num != 0;
        numCombo += num;
    }
    
    for(int i = 0; i < goldFishes.length; i++)
    {
        int num = duck.checkCollision(goldFishes[i]);
        retVal += num;
        colliding |= num != 0;
        numCombo += num / 2;
    }
    
    for(int i = 0; i < piranhas.length; i++)
    {
        int num = duck.checkCollision(piranhas[i]);
        if(num < 0)
        {
            for(int j = 0; j < hearts.length; j++) if(hearts[j].isVisible())
            {
                hearts[j].setVisible(false);
                break;
            }
            duck.setHurted();
        }
    }
    
    if(splash.isRunning()) splash.advance();
    
    if(colliding) duck.startEatingSound();
    
    duck.addCombo(numCombo);
    
    duck.advance(gameTicks, (previousColliding > 0) | colliding);
    
    previousColliding = (previousColliding << 1) & MASK;
    if(colliding) previousColliding |= 1;
    
    if(isAppearing)
    {
        numAppears++;
        
        if(numAppears == MAX_APPEARS)
        {
            isAppearing = false;
            numAppears = 0;
            
            if(bonus3.isVisible()) bonus3.setVisible(false);
            if(bonus4.isVisible()) bonus4.setVisible(false);
            if(bonus5.isVisible()) bonus5.setVisible(false);
            if(bonus6.isVisible()) bonus6.setVisible(false);
        }
    }
    
    if(duck.hasFinishedDiving())
    {
        if(!duck.wasHurted() && duck.getCombo() >= 3)
        {
            if(duck.getCombo() == 3)
            {
                bonus3.setVisible(true);
                retVal += 6;
            }
            else if(duck.getCombo() == 4)
            {
                bonus4.setVisible(true);
                retVal += 12;
            }
            else if(duck.getCombo() == 5)
            {
                bonus5.setVisible(true);
                retVal += 24;
            }
            else if(duck.getCombo() == 6)
            {
                bonus6.setVisible(true);
                retVal += 48;
            }
            
            isAppearing = true;
        }
        
        duck.resetHurted();
        duck.resetFinishDiving();
        duck.resetCombo();
    }
    
    for(int i = 0; i < clownFishes.length; i++) 
        clownFishes[i].advance(duck, gameTicks, myCurrentLeftX, myCurrentLeftX + DISP_WIDTH);
    
    for(int i = 0; i < goldFishes.length; i++)
        goldFishes[i].advance(duck, gameTicks, myCurrentLeftX, myCurrentLeftX + DISP_WIDTH);
    
    for(int i = 0; i < piranhas.length; i++)
        piranhas[i].advance(duck, gameTicks, myCurrentLeftX, myCurrentLeftX + DISP_WIDTH);
    
    return(retVal);
  }
}
